package com.lqd.mall.jpa.utils;


import com.lqd.mall.basis.utils.StringUtils;
import com.lqd.mall.jpa.constant.SqlUniversalConstants;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 封装一些简单的查询 实现通用的工具
 *
 * @author 零起点
 * @create 2022-3-7 16:16:32
 */
public class DynamicSqlUtil {

    public static <T> Example<T> setQueryConditions(T entity) {

        final ExampleMatcher[] matching = {ExampleMatcher.matching()};
        Map<String, Object> stringObjectMap = forAttributeFieldsValues(entity);
        if (stringObjectMap.size() == 0) {
            return Example.of(entity);
        }
        stringObjectMap.forEach((key, value) -> {
            // 判断 值的类型 分别做处理
            if (value instanceof String) {
                matching[0] = matching[0].withMatcher(key, ExampleMatcher.GenericPropertyMatcher::contains);
            } else {
                matching[0] = matching[0].withMatcher(key, ExampleMatcher.GenericPropertyMatcher::exact);
            }
        });
        return Example.of(entity, matching[0]);
    }

    private static <T> Map<String, Object> forAttributeFieldsValues(T entity) {
        Class<?> entityClass = entity.getClass();
        Field[] fields = getFields(entityClass);
        Map<String, Object> fieldConditions = new HashMap<>();
        for (Field field : fields) {
            if ("serialVersionUID".equals(field.getName())) {
                continue;
            }
            field.setAccessible(true);
            try {
                Object o = field.get(entity);
                if (Objects.isNull(o)) {
                    continue;
                }
                if (StringUtils.isEmpty(o.toString())) {
                    field.set(entity, null);
                    continue;
                }
                fieldConditions.put(field.getName(), o);
            } catch (IllegalAccessException e) {
                throw new RuntimeException("获取字段信息异常");
            }
        }
        return fieldConditions;
    }

    public static <T> String getTabaleName(T entity) {
        Class<?> entityClass = entity.getClass();
        Table table = entityClass.getAnnotation(Table.class);
        if (table == null) {
            return "";
        }
        return table.name();
    }

    public static <T> StringBuilder getWhere(T entity, Map<String, Object> params) {
        return generateQueryConditions(forFieldsValues(entity), params);
    }


    /**
     * 设置查询条件
     *
     * @param fieldInformation 需要添加的条件
     *                         kev:       字段名称
     *                         value:     查询条件对应的值
     * @param params           封装的查询条件值 并返回
     * @return 生成对应的sql语句
     */
    public static StringBuilder generateQueryConditions(Map<String, Object> fieldInformation, Map<String, Object> params) {
        // 保存对应的sql语句
        StringBuilder sql = new StringBuilder();
        // 判断是否为空
        if (fieldInformation == null || fieldInformation.isEmpty()) {
            return sql;
        }
        AtomicInteger index = new AtomicInteger(1);
        // 遍历Map集合
        fieldInformation.forEach((field, value) -> {
            // 判断 值的类型 分别做处理
            if (value instanceof String) {
                // 如果value为字符串 我们用对应的 like 去查询数据  如: name=40 得到的的sql 是 name like ?
                sql.append(field).append(SqlUniversalConstants.LIKE).append(SqlUniversalConstants.COLON.trim()).append(field);
                // 左右两边加上模糊查询 %
                value = SqlUniversalConstants.PERCENT + value + SqlUniversalConstants.PERCENT;
                // 添加查询条件, 这个不能写在外面
                params.put(field, value);

            } else if (value instanceof Iterable) {
                sql.append(field).append(SqlUniversalConstants.IN).append(SqlUniversalConstants.LEFT_PARENTHESIS);
                sql.append(SqlUniversalConstants.COLON.trim()).append(field).append(SqlUniversalConstants.RIGHT_PARENTHESIS);
                params.put(field, value);
            } else {
                // Number 判断这个父类 是 数字
                // 其他格式 用统一格式  = 拼接sql
                sql.append(field).append(SqlUniversalConstants.IS_EQUAL_TO_THE).append(SqlUniversalConstants.COLON.trim() + field.trim());
                // 添加数据到 条件里面
                params.put(field, value);
            }
            // 默认全部为AND拼接 这个可以扩展
            sql.append(SqlUniversalConstants.AND);
        });
        // 删除 最后一个" AND "符号
        if (sql.toString().endsWith(SqlUniversalConstants.AND)) {
            sql.delete(sql.lastIndexOf(SqlUniversalConstants.AND), sql.length());
        }
        //返回sql语句
        return sql;
    }


    public static <T> Map<String, Object> forFieldsValues(T entity) {

        Class<?> entityClass = entity.getClass();
        Field[] fields = getFields(entityClass);
        Map<String, Object> fieldConditions = new HashMap<>();
        for (Field field : fields) {
            if ("serialVersionUID".equals(field.getName())) {
                continue;
            }
            Column column = field.getAnnotation(Column.class);
            field.setAccessible(true);
            Transient aTransient = field.getAnnotation(Transient.class);

            if (aTransient != null) {
                continue;
            }
            // 字段名称
            String name = column.name();
            try {
                Object o = field.get(entity);
                if (Objects.isNull(o)) {
                    continue;
                }
                fieldConditions.put(name, o);
            } catch (IllegalAccessException e) {
                throw new RuntimeException("获取字段信息异常");
            }
        }
        return fieldConditions;
    }

    public static <T> String getIdField(T entity) {
        Class<?> entityClass = entity.getClass();
        Field[] fields = getFields(entityClass);
        for (Field field : fields) {
            if ("serialVersionUID".equals(field.getName())) {
                continue;
            }
            Id annotation = field.getAnnotation(Id.class);
            if (annotation != null) {
                Column column = field.getAnnotation(Column.class);
                if (column != null) {
                    return column.name();
                }
            }
        }
        return null;
    }

    private static Field[] getFields(Class annotation){
        List<Field> array = new ArrayList<Field>();
        while (annotation != null) {
            Field[] fields = annotation.getDeclaredFields();
            array.addAll(Arrays.asList(fields));
            annotation = annotation.getSuperclass();
        }
        return array.toArray(new Field[array.size()]);


    }
}